/*
 * Copyright 2008-2023 dexian.vip. All rights reserved.
 * Support: http://www.dexian.vip
 * License: http://www.dexian.vip/license
 */

package vip.dexian.core.base.service;


import vip.dexian.common.query.Filter;
import vip.dexian.common.query.Listable;
import vip.dexian.common.query.Page;
import vip.dexian.common.query.Pageable;
import vip.dexian.core.base.bean.BaseDTO;
import vip.dexian.core.base.bean.BaseEntity;
import vip.dexian.core.base.query.BaseQuery;

import java.io.Serializable;
import java.util.List;

/**
 * 业务逻辑基类处理
 *
 * @author 挺好的 2023年05月30日 18:59
 */
public interface BaseService<T extends BaseEntity <ID>, D extends BaseDTO <ID>, ID extends Serializable> {


    /**
     * 根据ID查找实体类，并转换为对应的DTO。该实体类处于托管状态。在同一个事务中，如果对该实体类进行属性修改，会发出update语句
     *
     * @param id
     *         ID
     *
     * @return 1. ID == null，返回null。2. 无法查找到数据，返回null。
     */
    D find (ID id);

    /**
     * 根据ID查找实体类。如果id == null || 无法查找到对应的数据，将抛出异常。该实体类处于托管状态。在同一个事务中，如果对该实体类进行属性修改，会发出update语句。
     *
     * @param id
     *         实体类ID
     * @param args
     *         国际化消息占位
     *
     * @return 1. ID == null。2. 无法查找到数据，throws ServiceValidationException。
     *
     * @throws vip.dexian.core.exception.ServiceValidationException
     *         当id == null || 无法查找到数据
     */
    D findByValidationIfNull (ID id, Object... args);

    /**
     * 根据条件查询数据
     *
     * @param filters
     *         搜索条件
     *
     * @return 条件为空，返回null
     */
    D find (List <Filter> filters);

    /**
     * 查询全部实体类。如果实体类继承自OrderEntity，按排序升序。否则按照ID降序
     *
     * @return 对应的实体列表
     */
    List <D> findAll ();

    /**
     * 查找全部的数据。如果没有指定排序条件，排序的方式同{@link BaseService#findAll()}。
     *
     * @param listable
     *         搜索条件，该条件即便指定了结果集的数量，该方法始终会查询全部数据，并且按照指定的排序和搜索条件进行检索数据
     *
     * @return 对应的实体列表
     */
    List <D> findAll (Listable listable);

    /**
     * 根据ID查询列表，该方法会校验会将重复的ID去除，使用IN查询。如果实体类继承自OrderEntity，按排序升序。否则按照ID降序
     *
     * @param ids
     *         id列表
     *
     * @return 对应的实体列表
     */
    List <D> findList (Long... ids);

    /**
     * 根据ID查询列表，该方法会校验会将重复的ID去除，使用IN查询。如果实体类继承自OrderEntity，按排序升序。否则按照ID降序
     *
     * @param ids
     *         id列表
     *
     * @return 对应的实体列表
     */
    List <D> findList (List <Long> ids);

    /**
     * 根据起始id和结束id查找列表。如果实体类继承自OrderEntity，按排序升序。否则按照ID降序
     *
     * @param begin
     *         开始id
     * @param end
     *         结束id
     *
     * @return 如果 begin is not Positive or end is not Positive，则返回空
     */
    List <D> findList (Long begin, Long end);

    /**
     * 查找列表。如果实体类继承自OrderEntity，按排序升序。否则按照ID降序
     *
     * @param listable
     *         列表参数
     *
     * @return 查找的实体类列表
     *
     * @see Listable
     */
    List <D> findList (Listable listable);

    /**
     * 根据属性模糊查找匹配的数据，最多只查询10条
     *
     * @param property
     *         属性名称
     * @param value
     *         属性值
     *
     * @return 属性名称或值为 empty，则返回 empty list。否则返还查找到的数据
     */
    List <D> findByProperty (String property, String value);

    /**
     * 分页查找数据。
     *
     * @param pageable
     *         搜索条件，包含客户端的搜索信息以及分页信息
     *
     * @return 分页数据
     */
    Page <D> findPage (Pageable pageable);

    /**
     * 分页查找数据，当{@link BaseService#findPage(vip.dexian.common.query.Pageable)}无法满足查询需求时，可以通过该方法扩展。
     *
     * @param pageable
     *         搜索条件，包含客户端的搜索信息以及分页信息
     * @param query
     *         自定义查询条件
     * @param <Q>
     *         自定义查询条件
     *
     * @return 分页数据
     */
    <Q extends BaseQuery> Page <D> findPage (Pageable pageable, Q query);

    /**
     * 根据id查找实体类是否存在
     *
     * @param id
     *         实体类id
     *
     * @return 如果id == null || 无法查找到数据，则返回false。否则返回true
     */
    boolean exists (ID id);

    /**
     * 根据条件查询是否存在。
     *
     * @param filters
     *         搜索条件。
     *
     * @return 指定条件下的查询出来的count>0，返回true，否则false
     */
    boolean exists (Filter... filters);

    /**
     * 根据条件查询是否存在
     *
     * @param filters
     *         搜索条件
     *
     * @return 指定条件下的查询出来的count>0，返回true，否则false
     */
    boolean exists (List <Filter> filters);


    /**
     * 保存实体类。持久化数据到数据库， 持久化完毕之后，实体类为托管状态。在同一个事务中，如果对该实体类进行属性修改，会发出update语句
     *
     * @param entity
     *         实体类
     *
     * @return 保存后的entity。
     */
    T save (T entity);

    /**
     * 更新实体类，如果实体类处于托管状态，则不进行查询，否则将会执行一次查询将实体类纳入持久化上下文管理，然后根据属性是否修改发出update语句
     *
     * @param entity
     *         实体类
     *
     * @return 更新后的entity
     */
    T update (T entity);

    /**
     * 更新实体类，如果实体类处于托管状态，则不进行查询，否则将会执行一次查询将实体类纳入持久化上下文管理，然后根据属性是否修改发出update语句
     *
     * @param entity
     *         实体类
     * @param ignoreNullProperty
     *         是否忽略null值的更新
     *
     * @return 更新后的entity
     */
    T update (T entity, boolean ignoreNullProperty);

    /**
     * 更新实体类。当实体类处于托管状态的时候，不能调用该方法。该方法会根据实体类的id进行一次查询，然后进行属性的复制操作，发现属性变更，则进行更新。否则不执行更新操作
     *
     * @param entity
     *         实体类。不可处于托管状态（即调用isManaged方法返回false）-> 游离状态。
     * @param ignoreProperties
     *         忽略的属性
     *
     * @return 更新后的entity
     */
    T update (T entity, String... ignoreProperties);

    /**
     * 更新实体类。当实体类处于托管状态的时候，不能调用该方法。该方法会根据实体类的id进行一次查询，然后进行属性的复制操作，发现属性变更，则进行更新。否则不执行更新操作
     *
     * @param entity
     *         实体类。不可处于托管状态（即调用isManaged方法返回false）-> 游离状态。
     * @param ignoreNullProperty
     *         是否忽略null值的更新
     * @param ignoreProperties
     *         忽略的属性
     *
     * @return 更新后的entity
     */
    T update (T entity, boolean ignoreNullProperty, String... ignoreProperties);

    /**
     * 根据ID删除实体类。该方法会先查询，如果存在就进行删除。默认执行的是“逻辑删除(更新isValid字段为false)”
     *
     * @param id
     *         实体类ID
     */
    void delete (ID id);

    /**
     * 根据id批量删除实体类
     *
     * @param ids
     *         id列表
     */
    void delete (ID... ids);

    /**
     * 根据id批量删除实体类
     *
     * @param ids
     *         id列表
     */
    void delete (List <ID> ids);

    /**
     * 根据id删除实体类。该方法会先查询，如果存在就进行删除。isRealDelete==true,执行物理删除。否则执行逻辑删除
     *
     * @param id
     *         实体类id
     * @param isRealDelete
     *         是否是物理删除
     */
    void delete (ID id, boolean isRealDelete);

    /**
     * 删除实体类。如果实体类不处于上下文管理状态，则通过实体类的ID重新从数据库中读取，然后执行删除。 默认执行的是“逻辑删除(更新isValid字段为false)”
     *
     * @param entity
     *         实体类
     */
    void delete (T entity);

    /**
     * 删除实体类。如果实体类不处于上下文管理状态，则通过实体类的ID重新从数据库中读取，然后执行删除。 isRealDelete==true,执行物理删除。否则执行逻辑删除
     *
     * @param entity
     *         实体类
     * @param isRealDelete
     *         是否是物理删除
     */
    void delete (T entity, boolean isRealDelete);


}
